/**
 * @file stack.hpp
 * @author 逆流 (1171267147@qq.com)
 * @brief
 * @version 0.1
 * @date 2024-10-15
 *
 * @copyright Copyright (c) 2024
 */

#ifndef INC_STL_STACK_HPP_
#define INC_STL_STACK_HPP_

#include <initializer_list>
#include <stdexcept>

#include "node.h"

namespace stl {

template <typename T>
class Stack {
public:
    Stack() = default;
    Stack(const std::initializer_list<T>& list) : top_(nullptr), length_(0) {
        for (const auto& val : list) {
            auto node  = new SingleNode<T>(val);
            node->next = top_;
            top_       = node;
            length_++;
        }
    }

    ~Stack() { Clear(); }

    std::size_t length() const { return length_; }

    bool Empty() const { return nullptr == top_; }

    void Clear() {
        while (top_ != nullptr) {
            auto next = top_->next;
            delete top_;
            top_ = next;
        }
        top_    = nullptr;
        length_ = 0;
    }

    void Push(const T& data) {
        auto node = new SingleNode<T>(data, top_);
        top_      = node;
        length_++;
    }

    T Pop() {
        if (Empty()) {
            throw std::out_of_range("stack is empty");
        }

        auto data = top_->data;
        auto next = top_->next;
        delete top_;
        top_ = next;

        length_--;

        return data;
    }

    T& Top() {
        if (Empty()) {
            throw std::out_of_range("stack is empty");
        }
        return top_->data;
    }

private:
    SingleNode<T>* top_    = nullptr;
    std::size_t    length_ = 0;
};

}  // namespace stl

#endif
